package org.batatasframework.support.searchable.writer;

import java.util.List;

import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.batatasframework.support.searchable.ResultHeadInfo;
import org.batatasframework.support.searchable.SearchableInputStream;
import org.batatasframework.support.searchable.result.ResultRow;

/*
 * 导出excel可能抛出了最大列数超过255列的异常
 * 为了避免此情况，统计时，尽量统计字段中内容重复那些字段
 * */
public class ExcelResultWriter extends AbstractResultWriter{
	private final XSSFSheet sheet;
	private final int skipRows;
	private final int skipCols;
	
	private int currentRowIndex = 0;
	private int currentColIndex = 0;
	private XSSFRow sheetRow;

	private int lineNumbers;
	private XSSFCellStyle headStyle;
	private XSSFCellStyle bodyStyle;
	
	public ExcelResultWriter(SearchableInputStream inputStream, XSSFSheet sheet)throws Exception{
		this(inputStream, sheet, 0, 0);
	}
	
	public ExcelResultWriter(SearchableInputStream inputStream, XSSFSheet sheet, int skipRows, int skipCols) throws Exception{
		super(inputStream);
		this.sheet = sheet;
		this.skipRows = skipRows;
		this.skipCols = skipCols;
	}
	
	@Override
	public void renderBody(List<? extends ResultRow> rows) throws Exception {
		if(null == bodyStyle){
			bodyStyle = sheet.getWorkbook().createCellStyle();
			bodyStyle.setVerticalAlignment(VerticalAlignment.CENTER);
			bodyStyle.setAlignment(HorizontalAlignment.LEFT);
			bodyStyle.setWrapText(true);//自动换行
		}
		super.renderBody(rows);
	}
	
	@Override
	protected void renderHead(ResultHeadInfo[][] heads) {
		currentRowIndex = skipRows;
		currentColIndex = skipCols + 1;//这里要跳过第一列，即“序号”列
		int headHeight = heads.length;
		if(null == headStyle){
			headStyle = sheet.getWorkbook().createCellStyle();
			headStyle.setVerticalAlignment(VerticalAlignment.CENTER);
			headStyle.setAlignment(HorizontalAlignment.CENTER_SELECTION);
			headStyle.setWrapText(true);//自动换行
		}
		
		XSSFRow sheetRow = _newLine(skipRows + headHeight);
		XSSFCell cell = _cell(sheetRow, skipCols);
//		cell.setCellValue("序号");
		cell.setCellStyle(headStyle);
		
		//
		
		int lastColIndex = 0, lastRowIndex = 0;
		
		/*
		 * 跨行表
		 * 注意：跨行表需要加上前面被跳过的部分，则前面跳过部分是不会被引用到的(浪费空间)；
		 *     如果不加上，则需要在下面的计算中currentColIndex的位置要减去相应跳过的列，
		 *     因为跨行表的下标是从0开始，而数据行并不一定是从0开始的，应该对应上。
		 *     由于统计市加了一个统计字段，而又还没有把旧的ColumnSize值改过来。所以inputStream.getColumnSize()+1，要不然会报数组越界异常。
		 */
		int[] spantable = new int[currentColIndex + inputStream.getColumnSize()+1];
		for(ResultHeadInfo[] li : heads){
			sheetRow = _newLine(currentRowIndex);
			for(ResultHeadInfo hi : li){
				
				/*
				 * 找出可以开始的列，如果当前的列刚好被跨行了，那么应该从下一个列开始
				 */
				while(spantable[currentColIndex] > 0){
					spantable[currentColIndex++]--;
				}
				
				cell = _cell(sheetRow, currentColIndex);
				cell.setCellValue(hi.getTitle());
				cell.setCellStyle(headStyle);
				/* 处理列的情况 */
				boolean needMerge = false;
				if(hi.getColspan() > 1){
					lastColIndex = currentColIndex + hi.getColspan();
					needMerge = true;
					
					/*
					 * 这里是需要跨列的情况，但如果跨的列中，已经有一个被用于跨行了，怎么办？
					 * 
					 * 如：第3行需要跨列3-10，其中第4列在第2行的时间被跨了列了。
					 * 
					 * ？？是否需要进行严格的限制？
					 */
				}else{
					lastColIndex = currentColIndex + 1;
				}
				
				/* 处理行的情况 */
				int rowspan = hi.getRowspan();
				if(rowspan > 1){
					lastRowIndex = currentRowIndex + rowspan;
					needMerge = true;
					
					//表示需要跨列的情况
					rowspan -= 1;
					for(int i = currentColIndex; i < lastColIndex; i++){
						spantable[i] = rowspan;
					}
				}else{
					lastRowIndex = currentRowIndex + 1;
					for(int i = currentColIndex; i < lastColIndex; i++){
						spantable[i] = 0;
					}
				}
				
				if(needMerge){
					sheet.addMergedRegion(new CellRangeAddress(
							currentRowIndex, 
							lastRowIndex - 1, 
							currentColIndex, 
							lastColIndex - 1));
				}
				
				currentColIndex = lastColIndex;
			}
			
			/*
			 * 把可用的行指向下一行
			 */
			currentRowIndex++;
			currentColIndex = skipCols + 1;
		}
		cell=_cell(sheetRow, 0);
		cell.setCellValue("序号");
		cell.setCellStyle(headStyle);
	}
	
	@Override
	public void group(Object value, int size) {
		_newLine();
		currentColIndex = skipCols;
		XSSFCell cell = _cell();
		Object[] v=(Object[]) value;
		String values="";
		for(Object o:v){
			values=values+o.toString();
		}
		cell.setCellValue(values);
		cell.setCellStyle(bodyStyle);
		sheetRow = null;
	}
	
	@Override
	public void newLine() {
		_newLine();
		lineNumbers++;
		currentColIndex = skipCols;
		XSSFCell cell = _cell();
		cell.setCellValue(String.valueOf(lineNumbers));
	}
	
	@Override
	public void append(Object value) {
		XSSFCell cell = _cell();
		if(null != value){
			cell.setCellValue(value.toString());
			cell.setCellStyle(bodyStyle);
		}else{
			cell.setCellValue("");
		}
	}
	
	private XSSFRow _newLine(int rowIndex) {
		XSSFRow sheetRow = sheet.getRow(rowIndex);
		if (sheetRow == null) {
			sheetRow = sheet.createRow(rowIndex);
		}
		return sheetRow;
	}
	
	private void _newLine() {
		sheetRow = _newLine(currentRowIndex);
		
		/*
		 * 当前的currentRowIndex是可以用的，用完再向下移动一行。
		 * 
		 * 如：开始设置为0，则表示从第一行开始写数据，则应该创建下标为0的一行，
		 * 创建成功后，当前的位置自动向下移动一行。
		 */
		currentRowIndex++;
	}
	
	private XSSFCell _cell(XSSFRow sheetRow, int colIndex){
		XSSFCell cell = sheetRow.getCell(colIndex);
		if (cell == null) {
			cell = sheetRow.createCell(colIndex);
		}
		return cell;
	}
	
	private XSSFCell _cell(){
		return _cell(sheetRow, currentColIndex++);
	}
}
